// src/composables/useHugeTextDownload.ts
import { ref, computed } from "vue";

export type NumberRow = {
  id?: number;
  countryCode: string;
  countryName?: string; // 允许可选，仍建议提供
  areaCode: string;
  snFrom: string; // 字符串，保留前导零
  snTo: string;
};

export type UseHugeTextDownloadOptions = {
  filename?: string; // 若提供则覆盖自动生成
  linesPerFlush?: number; // 每批写入多少行
  withBOM?: boolean; // 是否写入 UTF-8 BOM
  filenameStrategy?: (rows: NumberRow[], totalLines: bigint) => string;
};

export function useHugeTextDownload(options: UseHugeTextDownloadOptions = {}) {
  const filename = ref(options.filename ?? "numbers.txt");
  const LINES_PER_FLUSH = options.linesPerFlush ?? 50_000;
  const WITH_BOM = options.withBOM ?? true;

  // 默认文件名规则：countryName_areaCode_{总行数}.txt
  const defaultFilenameStrategy = (rows: NumberRow[], total: bigint) => {
    const first = rows[0];
    const countryName =
      (first?.countryName ?? "unknown")
        .replace(/[\\/:*?"<>|]/g, "_") // 兼容文件名非法字符
        .trim() || "unknown";
    const areaCode = (first?.areaCode ?? "NA").replace(/[\\/:*?"<>|]/g, "_");
    const totalStr = total.toString(); // 文件名中不加逗号，避免兼容性问题
    return `${countryName}_${areaCode}_${totalStr}.txt`;
  };

  const filenameStrategy = options.filenameStrategy ?? defaultFilenameStrategy;

  const saving = ref(false);
  const canceled = ref(false);
  const totalLines = ref<bigint>(0n);
  const writtenLines = ref<bigint>(0n);
  const percent = computed(() => {
    if (totalLines.value === 0n) return 0;
    const p = Number((writtenLines.value * 100n) / totalLines.value);
    return Math.min(100, Math.max(0, p));
  });

  let fileHandle: FileSystemFileHandle | null = null;
  let fileStream: FileSystemWritableFileStream | null = null;

  function formatBigInt(n: bigint): string {
    return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  }

  function calcTotalLines(rows: NumberRow[]): bigint {
    let total = 0n;
    for (const r of rows) {
      const from = BigInt(r.snFrom);
      const to = BigInt(r.snTo);
      if (to >= from) total += to - from + 1n;
    }
    return total;
  }

  function padBigInt(n: bigint, width: number): string {
    const s = n.toString();
    return s.length >= width ? s : "0".repeat(width - s.length) + s;
  }

  function* expandRowGenBigInt(r: NumberRow): Generator<string> {
    const prefix = `${r.countryCode}${r.areaCode}`;
    const width = Math.max(r.snFrom.length, r.snTo.length); // 修正：使用更大的位数
    let cur = BigInt(r.snFrom);
    const end = BigInt(r.snTo);
    for (; cur <= end; cur++) {
      yield `${prefix}${padBigInt(cur, width)}\n`;
    }
  }

  async function safeCloseStream() {
    try {
      if (fileStream) await fileStream.close();
    } catch {}
    fileStream = null;
    fileHandle = null;
  }

  async function safeAbortStream() {
    try {
      if (fileStream) await fileStream.abort();
    } catch {}
    fileStream = null;
    fileHandle = null;
  }

  async function pickFile(suggestedName?: string) {
    // @ts-ignore
    return window.showSaveFilePicker({
      suggestedName: suggestedName ?? filename.value,
      types: [{ description: "Text", accept: { "text/plain": [".txt"] } }]
    }) as Promise<FileSystemFileHandle>;
  }

  async function start(rows: NumberRow[], overrideFilename?: string) {
    if (!("showSaveFilePicker" in window)) {
      throw new Error(
        "当前浏览器不支持 File System Access API，请使用 Chrome/Edge 桌面版。"
      );
    }
    if (saving.value) return;

    // 先计算总行数，再生成文件名
    totalLines.value = calcTotalLines(rows);
    writtenLines.value = 0n;
    canceled.value = false;

    if (overrideFilename) {
      filename.value = overrideFilename;
    } else {
      filename.value = filenameStrategy(rows, totalLines.value);
    }

    // 选择保存位置（带上动态文件名）
    try {
      fileHandle = await pickFile(filename.value);
    } catch {
      // 用户取消选择文件
      return;
    }

    try {
      saving.value = true;

      fileStream = await fileHandle.createWritable();
      const encoder = new TextEncoder();

      if (WITH_BOM) {
        await fileStream.write(new Uint8Array([0xef, 0xbb, 0xbf]));
      }

      let buffer: string[] = [];
      let bufferedLines = 0;

      const flush = async () => {
        if (!fileStream || buffer.length === 0) return;
        const chunk = buffer.join("");
        buffer = [];
        await fileStream.write(encoder.encode(chunk));
      };

      for (const r of rows) {
        if (canceled.value) break;
        for (const line of expandRowGenBigInt(r)) {
          if (canceled.value) break;
          buffer.push(line);
          bufferedLines++;
          writtenLines.value += 1n;

          if (bufferedLines >= LINES_PER_FLUSH) {
            await flush();
            bufferedLines = 0;
            await new Promise(requestAnimationFrame); // 让出主线程
          }
        }
      }

      await flush();
      await safeCloseStream();
    } catch (e) {
      await safeAbortStream();
      throw e;
    } finally {
      saving.value = false;
    }
  }

  async function cancel() {
    if (!saving.value) return;
    canceled.value = true;
  }

  return {
    // state
    filename,
    saving,
    canceled,
    totalLines,
    writtenLines,
    percent,
    // helpers
    formatBigInt,
    // actions
    start,
    cancel
  };
}
